package com.andy.qi.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.andy.qi.conf.RoomServerConf;
import com.andy.qi.domain.room.Room;
import com.andy.qi.domain.room.RoomDr;
import com.andy.qi.domain.room.Seat;
import com.andy.qi.service.RoomMgr;
import com.andy.qi.service.SocketClient;
import com.andy.qi.service.TokenMgr;
import com.andy.qi.service.UserMgr;
import com.andy.qi.util.Json;
import com.andy.qi.util.StrUtils;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import com.fasterxml.jackson.databind.JsonNode;

@Component
public class SocketController extends WebApi {
    
    
    @Autowired private UserMgr userMgr;
    @Autowired private RoomMgr roomMgr;
    @Autowired private TokenMgr tokenMgr;
    @Autowired private RoomServerConf config;
    
    @OnConnect
    public void onConnect(SocketIOClient client)
    {
        System.out.println("=========onConnect======");
    }
    
    public static class LoginForm {
    	 public String token;
    	 public String roomId;
    	 public String time;
    	 public String sign;
    }
    
    @OnEvent(value = "login")
    public void login(SocketIOClient client, AckRequest request, String dataStr) {
        System.out.println("===============" + dataStr);
        SocketClient socket = SocketClient.from(client);
        JsonNode data = Json.toJsonNode(dataStr);
        
        String userId = socket.userId;
        if(userId != null){
            //已经登陆过的就忽略
            return;
        }
        String token = data.get("token").asText();
        String roomId = data.get("roomid").asText();
        String time = data.get("time").asText();
        String sign = data.get("sign").asText();

        System.out.println(roomId);
        System.out.println(token);
        System.out.println(time);
        System.out.println(sign);

        
        //检查参数合法性
        if(token == null || roomId == null || sign == null || time == null){
            System.out.println(1);
            socket.emit("login_result", new WebResult(1, "invalid parameters"));
            return;
        }
        
        //检查参数是否被篡改
        String md5 = StrUtils.md5(roomId + token + time + config.getRoomPriKey());
        if(!md5.equals(sign)){
            System.out.println(2);
            socket.emit("login_result", new WebResult(2,"login failed. invalid sign!"));
            return;
        }
        
        //检查token是否有效
        if(tokenMgr.isTokenValid(token)==false){
            System.out.println(3);
            socket.emit("login_result", new WebResult(3,"token out of time."));
            return;
        }
        
        //检查房间合法性
        userId = tokenMgr.getUserID(token);
        roomId = roomMgr.getUserRoom(userId);

        userMgr.bind(userId,socket);
        socket.userId = userId;

        //返回房间信息
        Room roomInfo = roomMgr.getRoom(roomId);
        
        int seatIndex = roomMgr.getUserSeat(userId);
        roomInfo.seats[seatIndex].ip = socket.address;

        Map<String, Object> userData = null;
        List<Map<String, Object>> seats = new ArrayList<>(roomInfo.seats.length);
        for(int i = 0; i < roomInfo.seats.length; ++i){
            Seat rs = roomInfo.seats[i];
            boolean online = false;
            if(rs.userId != null){
                online = userMgr.isOnline(rs.userId);
            }
            Map<String, Object> is = result();
            is.put("userid", rs.userId);
            is.put("ip", rs.ip);
            is.put("score", rs.score);
            is.put("name", rs.name);
            is.put("online", online);
            is.put("ready", rs.ready);
            is.put("seatindex", i);
            seats.add(is);

            if(userId.equals(rs.userId)){
                userData = is;
            }
        }

        //通知前端
        Map<String, Object> result = result();
        result.put("roomid", roomInfo.id);
        result.put("conf", roomInfo.conf);
        result.put("numofgames", roomInfo.numOfGames);
        result.put("seats", seats);
        
        socket.emit("login_result", new WebResult(0, "ok", result));

        //通知其它客户端
        userMgr.broacastInRoom("new_user_comes_push",userData,userId, false);
        
        socket.gameMgr = roomInfo.gameMgr;

        //玩家上线，强制设置为TRUE
        socket.gameMgr.setReady(userId);

        socket.emit("login_finished");

        if(roomInfo.dr != null){
            RoomDr dr = roomInfo.dr;
            long ramaingTime = (dr.endTime - System.currentTimeMillis()) / 1000;
            Map<String, Object> msg = result();
            msg.put("time", ramaingTime);
            msg.put("states", dr.states);
            userMgr.sendMsg(userId,"dissolve_notice_push",msg);    
        }
    }

    @OnEvent(value = "ready")
    public void ready(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        String userId = socket.userId;
        if(userId == null){
            return;
        }
        socket.gameMgr.setReady(userId);
        
        Map<String, Object> msg = result();
        msg.put("userid", userId);
        msg.put("ready", true);
        userMgr.broacastInRoom("user_ready_push", msg,userId,true);
    }

    //换牌
    @OnEvent(value = "huanpai")
    public void huanpai(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        if(socket.userId == null){
            return;
        }
        if(dataStr == null){
            return;
        }

        JsonNode data = Json.toJsonNode(dataStr);

        int p1 = data.get("p1").asInt();
        int p2 = data.get("p2").asInt();
        int p3 = data.get("p3").asInt();
        socket.gameMgr.huanSanZhang(socket.userId,p1,p2,p3);
    }

    //定缺
    @OnEvent(value = "dingque")
    public void dingque(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        if(socket.userId == null){
            return;
        }
        int que = Integer.valueOf(dataStr);
        socket.gameMgr.dingQue(socket.userId,que);
    }

    //出牌
    @OnEvent(value = "chupai")
    public void chupai(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        if(socket.userId == null){
            return;
        }
        int pai = Integer.valueOf(dataStr);
        socket.gameMgr.chuPai(socket.userId,pai);
    }
    
    //碰
    @OnEvent(value = "peng")
    public void peng(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        if(socket.userId == null){
            return;
        }
        socket.gameMgr.peng(socket.userId);
    }
    
    //杠
    @OnEvent(value = "gang")
    public void gang(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        if(socket.userId == null || dataStr == null){
            return;
        }
        int pai = Integer.valueOf(dataStr);
        socket.gameMgr.gang(socket.userId,pai);
    }
    
    //胡
    @OnEvent(value = "hu")
    public void hu(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        if(socket.userId == null){
            return;
        }
        socket.gameMgr.hu(socket.userId);
    }

    //过  遇上胡，碰，杠的时候，可以选择过
    @OnEvent(value = "guo")
    public void guo(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        if(socket.userId == null){
            return;
        }
        socket.gameMgr.guo(socket.userId);
    }
    
    //聊天
    @OnEvent(value = "chat")
    public void chat(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        if(socket.userId == null){
            return;
        }
        Map<String, Object> msg = result();
        msg.put("sender", socket.userId);
        msg.put("content",dataStr);
        userMgr.broacastInRoom("chat_push",msg,socket.userId,true);
    }
    
    //快速聊天
    @OnEvent(value = "quick_chat")
    public void quick_chat(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        if(socket.userId == null){
            return;
        }
        Map<String, Object> msg = result();
        msg.put("sender", socket.userId);
        msg.put("content",dataStr);
        userMgr.broacastInRoom("quick_chat_push",msg,socket.userId,true);
    }
    
    //语音聊天
    @OnEvent(value = "voice_msg")
    public void voice_msg(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        if(socket.userId == null){
            return;
        }
        Map<String, Object> msg = result();
        msg.put("sender", socket.userId);
        msg.put("content",dataStr);
        userMgr.broacastInRoom("voice_msg_push",msg,socket.userId,true);
    }
    
    //表情
    @OnEvent(value = "emoji")
    public void emoji(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        if(socket.userId == null){
            return;
        }
        Map<String, Object> msg = result();
        msg.put("sender", socket.userId);
        msg.put("content",dataStr);
        userMgr.broacastInRoom("emoji_push",msg,socket.userId,true);
    }
    
    //语音使用SDK不出现在这里
    
    //退出房间
    @OnEvent(value = "exit")
    public void exit(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        String userId = socket.userId;
        if(userId == null){
            return;
        }

        String roomId = roomMgr.getUserRoom(userId);
        if(roomId == null){
            return;
        }

        //如果游戏已经开始，则不可以
        if(socket.gameMgr.hasBegan(roomId)){
            return;
        }

        //如果是房主，则只能走解散房间
        if(roomMgr.isCreator(roomId, userId)){
            return;
        }
        
        //通知其它玩家，有人退出了房间
        userMgr.broacastInRoom("exit_notify_push",userId,userId,false);
        
        roomMgr.exitRoom(userId);
        userMgr.del(userId);
        
        socket.emit("exit_result");
        socket.disconnect();
    }
    
    //解散房间
    @OnEvent(value = "dispress")
    public void dispress(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        String userId = socket.userId;
        if(userId == null){
            return;
        }

        String roomId = roomMgr.getUserRoom(userId);
        if(roomId == null){
            return;
        }

        //如果游戏已经开始，则不可以
        if(socket.gameMgr.hasBegan(roomId)){
            return;
        }

        //如果不是房主，则不能解散房间
        if(roomMgr.isCreator(roomId,userId) == false){
            return;
        }
        
        userMgr.broacastInRoom("dispress_push",result(),userId,true);
        userMgr.kickAllInRoom(roomId);
        roomMgr.destroy(roomId);
        socket.disconnect();
    }

    //解散房间
    @OnEvent(value = "dissolve_request")
    public void dissolve_request(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        String userId = socket.userId;
        System.out.println(1);
        if(userId == null){
            System.out.println(2);
            return;
        }

        String roomId = roomMgr.getUserRoom(userId);
        if(roomId == null){
            System.out.println(3);
            return;
        }

        //如果游戏未开始，则不可以
        if(socket.gameMgr.hasBegan(roomId) == false){
            System.out.println(4);
            return;
        }

        Room ret = socket.gameMgr.dissolveRequest(roomId,userId);
        if(ret != null){
            RoomDr dr = ret.dr;
            long ramaingTime = (dr.endTime - System.currentTimeMillis()) / 1000;
            Map<String, Object> msg = result();
            msg.put("time", ramaingTime);
            msg.put("states", dr.states);
            System.out.println(5);
            userMgr.broacastInRoom("dissolve_notice_push",msg,userId,true);
        }
        System.out.println(6);
    }

    @OnEvent(value = "dissolve_agree")
    public void dissolve_agree(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        String userId = socket.userId;

        if(userId == null){
            return;
        }

        String roomId = roomMgr.getUserRoom(userId);
        if(roomId == null){
            return;
        }

        Room ret = socket.gameMgr.dissolveAgree(roomId,userId,true);
        if(ret != null){
            RoomDr dr = ret.dr;
            long ramaingTime = (dr.endTime - System.currentTimeMillis()) / 1000;
            Map<String, Object> msg = result();
            msg.put("time", ramaingTime);
            msg.put("states", dr.states);
            userMgr.broacastInRoom("dissolve_notice_push",msg,userId,true);

            boolean doAllAgree = true;
            for(int i = 0; i < dr.states.length; ++i){
                if(dr.states[i] == false){
                    doAllAgree = false;
                    break;
                }
            }

            if(doAllAgree){
                socket.gameMgr.doDissolve(roomId);                  
            }
        }
    }

    @OnEvent(value = "dissolve_reject")
    public void dissolve_reject(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        String userId = socket.userId;

        if(userId == null){
            return;
        }

        String roomId = roomMgr.getUserRoom(userId);
        if(roomId == null){
            return;
        }

        Room ret = socket.gameMgr.dissolveAgree(roomId,userId,false);
        if(ret != null){
            userMgr.broacastInRoom("dissolve_cancel_push",result(),userId,true);
        }
    }

    //断开链接
    @OnEvent(value = "disconnect")
    public void disconnect(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        String userId = socket.userId;
        if(userId == null){
            return;
        }
        Map<String, Object> msg = result();
        msg.put("userid", userId);
        msg.put("online", false);

        //通知房间内其它玩家
        userMgr.broacastInRoom("user_state_push",msg,userId, false);

        //清除玩家的在线信息
        userMgr.del(userId);
        socket.userId = null;
    }
    
    @OnEvent(value = "game_ping")
    public void game_ping(SocketIOClient client, AckRequest request, String dataStr) {
        SocketClient socket = SocketClient.from(client);
        String userId = socket.userId;
        if(userId == null){
            return;
        }
        socket.emit("game_pong");
    }
    
}